package wjl.awesome.virus.controller;

import lombok.extern.log4j.Log4j2;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.util.StringUtils;
import wjl.awesome.virus.data.CsvDao;
import wjl.awesome.virus.data.CsvDaoQo;
import wjl.awesome.virus.exception.MyException;

import javax.validation.constraints.NotNull;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 功能简述：
 用户可以通过api获取目前各个国家确诊人数    ====》 地图
用户可以通过api 获取各个国家 新增病例      =====》 地图 !

 用户可以通过api查询某个国家过去一定时间内 疫情趋势  ===》图表




 1、 使用Java 8的Stream API可以很方便地访问集合类型对象，如：List ；
 2、 parallelStream支持并行流，可以大大提升访问性能；
 3、 filter方法支持设置过滤条件；
 4、 Collectors.toUnmodifiableList()收集为不可变的List集合。
 11、 定义前端数据展示页面。
 可以使用 任何视图引擎 或 任何前端框架 构建前端数据展示。
 要求：界面美观、整洁，支持查询功能。如果页面包含图表展示功能，加15分。


 点击按钮

 * @author 吴经纶
 * @blame Android Team
 */

@RestController
@Log4j2
public class SearchController {

    /**
     *以日期作为索引  作为一级缓存
     * 存储某一天 所有国家的信息
     * 以便于不同用户 查询相同日期时的效率
     * */
    private static final Map<String, Map<String,CsvDao>> VIRUS_DATE_CACHE = new ConcurrentHashMap<>();
    /**
     *以国家名称作为索引  作为一级缓存
     * 存储某一天 所有国家的信息
     * 以便于不同用户 查询相同日期时的效率
     * */
    private static final Map<String, List<CsvDao>> VIRUS_COUNTRY_CACHE = new ConcurrentHashMap<>();
    private static final String LOCAL_PATH =System.getProperty("user.dir")+File.separator+"src"+File.separator+"main"+ File.separator+"resources"+File.separator+"static"+File.separator;

    /**
     *
     * 用户可以通过api获取某个国家过去7天确诊人数
     *
    * */

    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET,path = "/api/search_country/seven_day/{Country}")
    public   CsvDaoQo getVirusViewByLast7Day(@NotNull @PathVariable String Country) throws MyException {
        String country= Country.toLowerCase();
        try {
            FileReader fileReader = new FileReader(LOCAL_PATH+"time_series_covid19_confirmed_global.csv");
            final CSVParser csvParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(fileReader);
            @NotNull String finalCountry = country;
            List<CsvDaoQo> csvDaos =  csvParser.getRecords()
                    .parallelStream()
                    .filter(r-> finalCountry.equals(r.get(1).toLowerCase()))
                    .map((r)->
                                CsvDaoQo.builder()
                                        .province(r.get(0))
                                        .country(r.get(1))
                                        .lat(r.get(2))
                                        .Long(r.get(3))
                                        .DayOne(r.get(r.size()-7))
                                        .DayTwo(r.get(r.size()-6))
                                        .DayThree(r.get(r.size()-5))
                                        .DayFour(r.get(r.size()-4))
                                        .DayFive(r.get(r.size()-3))
                                        .DaySix(r.get(r.size()-2))
                                        .DaySeven(r.get(r.size()-1))
                                        .build()
                            )
                    .collect(Collectors.toUnmodifiableList());
            Map<String,CsvDaoQo> map = new HashMap<>(8);
            for (CsvDaoQo c:csvDaos
            ) {
                String temp = c.getCountry();
                int dayOne = Integer.parseInt(c.getDayOne());
                int dayTwo = Integer.parseInt(c.getDayTwo());
                int dayThree = Integer.parseInt(c.getDayThree());
                int dayFour = Integer.parseInt(c.getDayFour());
                int dayFive = Integer.parseInt(c.getDayFive());
                int daySix = Integer.parseInt(c.getDaySix());
                int daySeven = Integer.parseInt(c.getDaySeven());

                if (map.containsKey(temp))
                {
                    int oldDayOne = Integer.parseInt(map.get(temp).getDayOne());
                    int oldDayTwo = Integer.parseInt(map.get(temp).getDayTwo());
                    int oldDayThree = Integer.parseInt(map.get(temp).getDayThree());
                    int oldDayFour = Integer.parseInt(map.get(temp).getDayFour());
                    int oldDayFive = Integer.parseInt(map.get(temp).getDayFive());
                    int oldDaySix = Integer.parseInt(map.get(temp).getDaySix());
                    int oldDaySeven = Integer.parseInt(map.get(temp).getDaySeven());
                    c.setDayOne(String.valueOf(oldDayOne+dayOne));
                    c.setDayTwo(String.valueOf(oldDayTwo+dayTwo));
                    c.setDayThree(String.valueOf(oldDayThree+dayThree));
                    c.setDayFour(String.valueOf(oldDayFour+dayFour));
                    c.setDayFive(String.valueOf(oldDayFive+dayFive));
                    c.setDaySix(String.valueOf(oldDaySix+daySix));
                    c.setDaySeven(String.valueOf(oldDaySeven+daySeven));
                    map.put(temp,c);
                }
                else
                {
                    map.put(temp,c);
                }
            }

            return map.get(Country);
        } catch (Exception e)
        {
            e.printStackTrace();
            throw new MyException("无法正确读取该日疫情数据");
        }
    }







    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET,path = "/api/search_time/{time}")
    public Map<String,CsvDao> getVirusViewByTime(@NotNull @PathVariable String time) throws MyException {
        time = StringUtils.replace(time,"-","/");
        if (VIRUS_DATE_CACHE.containsKey(time))
        {
            return VIRUS_DATE_CACHE.get(time);
        }
        try {
            FileReader fileReader = new FileReader(LOCAL_PATH+"time_series_covid19_confirmed_global.csv");
            final CSVParser csvParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(fileReader);
            @NotNull String finalTime = time;
            List<CsvDao> csvDaos =  csvParser.getRecords()
                    .parallelStream()
                    .filter(r-> !"0".equals(r.get(r.size()-1)))
                    .map(r-> CsvDao.builder()
                            .province(r.get(0))
                            .country(r.get(1))
                            .lat(r.get(2))
                            .Long(r.get(3))
                            .number(r.get(finalTime))
                            .build())
                    .collect(Collectors.toUnmodifiableList());
            Map<String,CsvDao> map = new HashMap();
            for (CsvDao c:csvDaos
                 ) {
                String country = c.getCountry();
                int newNum = Integer.parseInt(c.getNumber());

                if (map.containsKey(country))
                {
                    int oldNum = Integer.parseInt(map.get(country).getNumber());
                    c.setNumber(String.valueOf(newNum+oldNum));
                    map.put(country,c);
                }
                else
                {
                    map.put(country,c);
                }
            }

            VIRUS_DATE_CACHE.put(time,map);
            return map;
        } catch (Exception e)
        {
            e.printStackTrace();
            throw new MyException("无法正确读取该日疫情数据");
        }
    }
/**
 * 用户可以通过api查询某个国家过去一定时间内 疫情趋势  ===》图表
 **/
    @GetMapping("/api/search_country/{country}")
    @CrossOrigin
    public List<CsvDao> getVirusViewByCountry(@NotNull @PathVariable String country) throws MyException {
        log.info(LOCAL_PATH );

        if (VIRUS_COUNTRY_CACHE.containsKey(country))
        {
            log.info("hits");
            return VIRUS_COUNTRY_CACHE.get(country);
        }
        try {
            FileReader fileReader = new FileReader(LOCAL_PATH+"time_series_covid19_confirmed_global.csv");
            final CSVParser csvParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(fileReader);
            List<CsvDao> csvDaos =
                    csvParser.getRecords()
                    .parallelStream()
                    .filter(r-> !"0".equals(r.get(r.size()-1)))
                            .filter(r->{
                                return r.get(1).toLowerCase().equals(StringUtils.toLowerCase(country, Locale.ENGLISH));
                            })
                    .map(r-> {
                        HashMap<String,String> temp= new HashMap<>( r.toMap());
                        temp.remove("Province/State");
                        temp.remove("Country/Region");
                        temp.remove("Lat");
                        temp.remove("Long");

                        CsvDao csvDao =  CsvDao.builder()
                            .province(r.get(0))
                            .country(r.get(1))
                            .lat(r.get(2))
                            .Long(r.get(3))
                            .dateMap(temp)
                            .number(r.get(r.size()-1))
                            .build();

                            return csvDao;
                    })
                    .collect(Collectors.toUnmodifiableList());
            VIRUS_COUNTRY_CACHE.put(country,csvDaos);
            log.info(csvDaos);
            return csvDaos;
//            return null;
        } catch (Exception e)
        {
            e.printStackTrace();
            throw new MyException("无法正确读取该日疫情数据");
        }
    }

}
